/*
 * Copyright 2003-2005 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

#include "Types.h"

#include "TypeMap.h"

static struct type_map_vtable typeMapVtable =
{
	&_type_map_map,
	&_type_map_get_id,
	&_type_map_get_name,
	&_type_map_set_reader,
	&_type_map_set_writer,
	&_type_map_get_reader,
	&_type_map_get_writer,
	&_type_map_get_structure,
	&_type_map_get_library_id,
	&_type_map_get_mapped_id,
	&_type_map_is_valid_id,
	&_type_map_is_valid_name,
	&_type_map_get_size
};

typedef struct type_map_item
{
	type_reader reader;
	type_writer writer;
} 
type_map_item;

void type_map_init( type_map * map, type_library * library )
{
	map->__vt = &typeMapVtable;
	map->library = library;
	intmap_init( &map->map, 4 );
}

void type_map_destroy( type_map * map )
{
	
}

int _type_map_map( type_map * map, int id, int systemid )
{
	type_map_item * data;
	int i;

	if ( systemid <= NOTYPE  )
		return TYPE_INVALID_PARAM;

	/* check if it hasn't already been mapped. */
	i = type_map_get_library_id( map, id );
	if ( i > NOTYPE )
	{
		if ( i != systemid )
			return TYPE_INVALID_PARAM;
			
		/* already mapped to the same value. */
		return TYPE_OK;
	}

	data = (type_map_item *) type_malloc( sizeof(type_map_item) );
	data->reader.reader = NULL;
	data->reader.data = NULL;
	data->writer.writer = NULL;
	data->writer.data = NULL;
				
	intmap_add( &map->map, id,  systemid, data );	
	return TYPE_OK;
}

int _type_map_get_id( type_map * map, type_name * name )
{
	int id, i;

	i = type_library_get_id( map->library, name );
	if ( i <= NOTYPE )
	{
		return i;
	}
	
	id = intmap_find_key( &map->map, i );
	if ( id != TYPE_OK )
		return TYPE_NOT_MAPPED;

	return intmap_key( &map->map );
}

type_name * _type_map_get_name( type_map * map, int id )
{
	int libraryId = type_map_get_library_id( map, id );
	if ( libraryId <= NOTYPE )
		return NULL;
	
	return type_library_get_name( map->library, libraryId );
}

int _type_map_set_reader( type_map * map, int id, typeReader reader, void * readerData )
{
	struct type_map_item * item;
	int i;

	if ( id <= NOTYPE )
		return NOTYPE;
	
	i = intmap_find( &map->map, id );
	if ( i <= -1 )
		return TYPE_NOT_MAPPED;
	
	item = (type_map_item *) intmap_data( &map->map );
	if ( item == NULL )
		return TYPE_NOT_MAPPED;
		
	item->reader.reader = reader;
	item->reader.data = readerData;
	return TYPE_OK;
}

int _type_map_set_writer( type_map * map, int id, typeWriter writer, void * writerData )
{
	type_map_item * item;
	int i;

	if ( id <= NOTYPE )
		return NOTYPE;
	
	i = intmap_find( &map->map, id );
	if ( i <= -1 )
		return TYPE_NOT_MAPPED;
	
	item = (type_map_item *) intmap_data( &map->map );
	if ( item == NULL )
		return TYPE_NOT_MAPPED;
		
	item->writer.writer = writer;
	item->writer.data = writerData;
	return TYPE_OK;
}


type_reader * _type_map_get_reader( type_map * map, int id )
{
	type_map_item * item;
	int libraryId;

	libraryId = type_map_get_library_id( map, id );
	if ( libraryId <= NOTYPE )
		return NULL;

	item = (type_map_item *) intmap_data( &map->map );
	if ( item == NULL )
		return type_library_get_reader( map->library, libraryId );

	if ( item->reader.reader == NULL )
	{
		type_reader * reader = type_library_get_reader( map->library, libraryId );
		item->reader.reader = reader->reader;
		item->reader.data = reader->data;
	}	
	return &(item->reader);
}

type_writer * _type_map_get_writer( type_map * map, int id )
{
	type_map_item * item;
	int libraryId;

	libraryId = type_map_get_library_id( map, id );
	if ( libraryId <= NOTYPE )
		return NULL;

	item = intmap_data( &map->map );
	if ( item == NULL )
		return type_library_get_writer( map->library, libraryId );

	if ( item->writer.writer == NULL )
	{
		type_writer * writer = type_library_get_writer( map->library, libraryId );
		item->writer.writer = writer->writer;
		item->writer.data = writer->data;
	}	
	return &(item->writer);
}

type_element * _type_map_get_structure( type_map * map, int id )
{
	int libraryId = type_map_get_library_id( map, id );
	if ( libraryId <= NOTYPE )
		return NULL;
	
	return type_library_get_structure( map->library, libraryId );
}

int _type_map_get_library_id( type_map * map, int id )
{
	int i;

	if ( id <= NOTYPE )
		return NOTYPE;
	
	i = intmap_find( &map->map, id );
	if ( i <= -1 )
		return TYPE_NOT_MAPPED;
		
	return intmap_value( &map->map );	
}

int _type_map_get_mapped_id( type_map * map, int systemId )
{
	int i;

	if ( systemId <= NOTYPE )
		return TYPE_INVALID_PARAM;
	
	i = intmap_find_key( &map->map, systemId );		
	if ( i <= NOTYPE )
		return TYPE_NOT_MAPPED;
	
	return intmap_key( &map->map );
}

bool _type_map_is_valid_id( type_map * map, int id )
{
	int i = intmap_find( &map->map, id );
	if ( i <= NOTYPE )
		return false;
				
	return true;
}

bool _type_map_is_valid_name( type_map * map, type_name * name )
{
	int i, mid;

	i = type_library_get_id( map->library, name );
	if ( i <= NOTYPE )
		return false;
	
	mid = intmap_find_key( &map->map, i );
	if ( mid <= NOTYPE )
		return false;
				
	return true;
}

int _type_map_get_size( type_map * map )
{
	return intmap_size( &map->map );
}

void type_map_iterator_init( type_map_iterator * iter, type_map * map )
{
	intmap_iterator_init( &iter->iter, &map->map );
}

bool type_map_iterator_next( type_map_iterator * iter )
{
	return intmap_iterator_next( &iter->iter );
}

int type_map_iterator_id( type_map_iterator * iter )
{
	return intmap_iterator_key( &iter->iter );
}


